﻿// <copyright file="KinectDelayActionTrigger.cs" company="Ucaya">
// </copyright>
// <author>Ucaya</author>

namespace KinectExtensions.Interactivity
{
    #region

    using System;
    using System.ComponentModel;
    using System.ComponentModel.Composition;
    using System.Windows;
    using System.Windows.Media;

    using KinectExtensions.Nui;
    using KinectExtensions.Services;

    #endregion

    /// <summary>
    ///   TODO: Update summary.
    /// </summary>
    public class KinectDelayActionTrigger : KinectOverTrigger
    {
        #region Constants and Fields

        /// <summary>
        ///   HoverDuration depedency property.
        /// </summary>
        public static readonly DependencyProperty HoverDurationProperty = DependencyProperty.Register("HoverDuration", typeof(TimeSpan), typeof(KinectDelayActionTrigger), new PropertyMetadata(TimeSpan.FromSeconds(2), (d, e) => ((KinectDelayActionTrigger)d).OnHoverDurationChanged((TimeSpan)e.OldValue, (TimeSpan)e.NewValue)));

        /// <summary>
        ///   IsMagneticZone depedency property.
        /// </summary>
        public static readonly DependencyProperty IsMagneticZoneProperty = DependencyProperty.Register("IsMagneticZone", typeof(bool), typeof(KinectDelayActionTrigger), null);

        /// <summary>
        ///   The last master.
        /// </summary>
        private HandPosition lastMaster;

        /// <summary>
        ///   The last zone.
        /// </summary>
        private HoverKinectZone lastZone;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets HandTrackingService.
        /// </summary>
        [Import]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public HandTrackingService HandTrackingService { get; set; }

        /// <summary>
        ///   Gets or sets HoverDuration.
        /// </summary>
        public TimeSpan HoverDuration
        {
            get
            {
                return (TimeSpan)this.GetValue(HoverDurationProperty);
            }

            set
            {
                this.SetValue(HoverDurationProperty, value);
            }
        }

        /// <summary>
        ///   Gets or sets a value indicating whether IsMagneticZone.
        /// </summary>
        public bool IsMagneticZone
        {
            get
            {
                return (bool)this.GetValue(IsMagneticZoneProperty);
            }

            set
            {
                this.SetValue(IsMagneticZoneProperty, value);
            }
        }

        #endregion

        #region Methods

        protected override void HitTestAssodiatedObject(out bool isOver, out Point overPosition)
        {
            if (this.AssociatedObject != null)
            {
                HitResult hitResult = this.HitTestService.HitTestHandMaster(this.AssociatedObject);
                if (hitResult.CurrentKinectZone != null && hitResult.CurrentKinectZone != this.lastZone)
                {
                    isOver = false;
                }
                else
                {
                    isOver = hitResult.Result;
                }

                overPosition = new Point(hitResult.RelativeTouchPosition.X, hitResult.RelativeTouchPosition.Y);
            }
            else
            {
                isOver = false;
                overPosition = new Point();
            }
        }

        /// <summary>
        ///   handles the IsKinectOverProperty changes.
        /// </summary>
        /// <param name = "oldValue">
        ///   The old value.
        /// </param>
        /// <param name = "newValue">
        ///   The new value.
        /// </param>
        protected override void OnIsKinectOverChanged(bool oldValue, bool newValue)
        {
            HandPosition master = this.HandTrackingService.HandMaster;
            if (this.lastMaster != null)
            {
                if (this.lastZone == this.lastMaster.KinectZone)
                {
                    this.lastMaster.KinectZone = null;
                }
            }

            if (this.lastZone != null)
            {
                this.lastZone.Leave();
            }

            this.lastMaster = master;
            if (newValue)
            {
                HoverKinectZone hoverZone;
                if (this.IsMagneticZone)
                {
                    Window h = Application.Current.MainWindow;
                    if (h == null)
                    {
                        return;
                    }

                    var magneticZone = new MagneticHoverKinectZone();
                    hoverZone = magneticZone;
                    Rect bounds = VisualTreeHelper.GetDescendantBounds(this.AssociatedObject);
                    Point center = this.AssociatedObject.TransformToVisual(h).Transform(new Point(bounds.X + (bounds.Width / 2), bounds.Y + (bounds.Height / 2)));
                    magneticZone.MagneticCenter = center;
                }
                else
                {
                    hoverZone = new HoverKinectZone();
                }

                hoverZone.HoverActionDelayDuration = this.HoverDuration;
                hoverZone.Action = () =>
                    {
                        this.InvokeActions(null);
                    };
                hoverZone.Enter();

                this.lastZone = hoverZone;
                this.lastMaster.KinectZone = hoverZone;
            }
        }

        /// <summary>
        ///   handles the HoverDurationProperty changes.
        /// </summary>
        /// <param name = "oldValue">
        ///   The old value.
        /// </param>
        /// <param name = "newValue">
        ///   The new value.
        /// </param>
        private void OnHoverDurationChanged(TimeSpan oldValue, TimeSpan newValue)
        {
        }

        #endregion
    }
}